package co.edu.eam.iso.view;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.swing.ButtonGroup;
import javax.swing.DefaultListModel;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.ListSelectionModel;
import javax.swing.border.EmptyBorder;
import javax.swing.border.EtchedBorder;
import javax.swing.border.TitledBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import org.jfree.ui.ExtensionFileFilter;

import co.edu.eam.iso.chart.CharGenerator;
import co.edu.eam.iso.chart.model.ChartData;
import co.edu.eam.iso.enums.CharacteristicEnum;
import co.edu.eam.iso.enums.IconEnum;
import co.edu.eam.iso.enums.SubCharacteristicEnum;
import co.edu.eam.iso.evaluated.CharacteristicEvaluated;
import co.edu.eam.iso.evaluated.ProductEvaluated;
import co.edu.eam.iso.evaluated.SubCharacteristicEvaluated;
import co.edu.eam.iso.excel.ExcelReader;
import co.edu.eam.iso.logger.Logger;
import co.edu.eam.iso.view.listmodel.EvaluationListModel;

/**
 * @author Giovanny Ramirez
 */
public class GenerateReportsDialog extends JDialog {

	private static final long serialVersionUID = 1L;

	private static final int NOT_SELECTED = -1;

	private Component parent;

	private JPanel contentPane;
	private JPanel panelChart;

	private DefaultListModel listModelProducts;

	private JList listProducts;
	private JList listEvaluations;

	private JButton btnRemoveProduct;
	private JButton btnAddEvaluation;
	private JButton btnRemoveEvaluation;

	private JRadioButton radioButtonTotal;
	private JRadioButton radioButtonChrtcs;
	private JRadioButton radioButtonSubChrtcs;
	private JCheckBox checkBoxIncludeValue;

	private Map<String, EvaluationListModel> evaluationMap;

	public GenerateReportsDialog(Component parent) {
		this.parent = parent;
		this.evaluationMap = new HashMap<String, EvaluationListModel>();
		initialize();
	}

	private void initialize() {
		setTitle("ISO 9126-1 - Generar reportes");
		setBounds(100, 100, 905, 635);
		setModalityType(ModalityType.APPLICATION_MODAL);
		setDefaultCloseOperation(DISPOSE_ON_CLOSE);
		setResizable(false);
		setLocationRelativeTo(parent);

		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		contentPane.setLayout(null);
		contentPane.add(createPanelReports());
		setContentPane(contentPane);

		JButton btnCancel = new JButton("Cancelar");
		btnCancel.setBounds(800, 570, 90, 25);
		contentPane.add(btnCancel);
		btnCancel.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				closeWindow();
			}
		});
	}

	private ImageIcon getIcon(IconEnum icon) {
		return new ImageIcon(getClass().getResource(icon.getLocation()));
	}

	private void closeWindow() {
		dispose();
	}

	private JPanel createPanelReports() {
		JPanel panelReports = new JPanel();
		panelReports.setBorder(new TitledBorder(null, "Reportes",
				TitledBorder.LEADING, TitledBorder.TOP, null, null));
		panelReports.setBounds(5, 5, 890, 560);
		panelReports.setLayout(null);

		panelReports.add(createPanelProducts());
		panelReports.add(createPanelEvaluations());
		panelReports.add(createPanelOptions());
		panelReports.add(createPanelChart());

		return panelReports;
	}

	private JPanel createPanelChart() {
		panelChart = new JPanel();
		panelChart.setBackground(Color.WHITE);
		panelChart.setLayout(new BorderLayout());
		panelChart
				.setBorder(new EtchedBorder(EtchedBorder.LOWERED, null, null));
		panelChart.setBounds(210, 30, 660, 506);

		return panelChart;
	}

	private JPanel createPanelProducts() {
		JPanel panelProducts = new JPanel();
		panelProducts.setLayout(null);
		panelProducts.setBorder(new EtchedBorder(EtchedBorder.LOWERED, null,
				null));
		panelProducts.setBounds(20, 30, 185, 150);

		JLabel lblProducts = new JLabel("Productos:");
		lblProducts.setFont(new Font("Tahoma", Font.BOLD, 12));
		lblProducts.setBounds(15, 10, 80, 15);
		panelProducts.add(lblProducts);

		listModelProducts = new DefaultListModel();

		listProducts = new JList();
		listProducts.setModel(listModelProducts);
		listProducts
				.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
		listProducts.addMouseListener(new MouseAdapter() {
			public void mouseClicked(MouseEvent e) {
				if (listProducts.getSelectedIndex() != NOT_SELECTED) {
					btnRemoveProduct.setEnabled(true);
					btnAddEvaluation.setEnabled(true);
					btnRemoveEvaluation.setEnabled(false);
					listEvaluations.setModel(evaluationMap.get(listProducts
							.getSelectedValue().toString()));
				}
			}
		});

		listProducts.addListSelectionListener(new ListSelectionListener() {
			public void valueChanged(ListSelectionEvent e) {
				if (listProducts.getSelectedIndex() != NOT_SELECTED) {
					btnRemoveProduct.setEnabled(true);
					btnAddEvaluation.setEnabled(true);
					btnRemoveEvaluation.setEnabled(false);
					listEvaluations.setModel(evaluationMap.get(listProducts
							.getSelectedValue().toString()));

					if (listProducts.getSelectedValues().length == 1 
							&& !radioButtonTotal.isSelected()) {
						checkBoxIncludeValue.setEnabled(true);
					} else {
						checkBoxIncludeValue.setEnabled(false);
						checkBoxIncludeValue.setSelected(false);
					}
				}
			}
		});

		JScrollPane scrollPaneProducts = new JScrollPane();
		scrollPaneProducts.setBounds(55, 35, 120, 100);
		scrollPaneProducts.setViewportView(listProducts);
		panelProducts.add(scrollPaneProducts);

		JButton btnAddProduct = new JButton();
		btnAddProduct.setToolTipText("Agregar");
		btnAddProduct.setBounds(15, 35, 35, 35);
		btnAddProduct.setIcon(getIcon(IconEnum.ADD));
		btnAddProduct.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				addProduct();
			}
		});
		panelProducts.add(btnAddProduct);

		btnRemoveProduct = new JButton();
		btnRemoveProduct.setEnabled(false);
		btnRemoveProduct.setToolTipText("Quitar");
		btnRemoveProduct.setBounds(15, 71, 35, 35);
		btnRemoveProduct.setIcon(getIcon(IconEnum.REMOVE));
		btnRemoveProduct.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				int option = JOptionPane.showConfirmDialog(
						GenerateReportsDialog.this,
						"¿Está seguro de eliminar el producto?");

				if (option == JOptionPane.YES_OPTION) {
					int index = listProducts.getSelectedIndex();
					evaluationMap.remove(listProducts.getSelectedValue()
							.toString());
					listModelProducts.removeElementAt(index);
					btnRemoveProduct.setEnabled(false);
					btnRemoveEvaluation.setEnabled(false);

					DefaultListModel listModel = (DefaultListModel) listEvaluations
							.getModel();
					listModel.removeAllElements();

					if (listModelProducts.getSize() == 0) {
						btnAddEvaluation.setEnabled(false);
					}
				}
			}
		});
		panelProducts.add(btnRemoveProduct);

		return panelProducts;
	}

	private void addProduct() {
		String productName = JOptionPane.showInputDialog(this,
				"Ingrese el nombre del producto.");

		if (productName != null && !productName.isEmpty()) {
			productName = productName.trim();

			if (evaluationMap.get(productName) == null) {
				evaluationMap.put(productName, new EvaluationListModel());
				listModelProducts.addElement(productName);
			} else {
				JOptionPane.showMessageDialog(GenerateReportsDialog.this,
						"Ya existe un producto con el mismo nombre.");
				addProduct();
			}
		} else if (productName != null && productName.isEmpty()) {
			JOptionPane.showMessageDialog(this,
					"Debe ingresar el nombre del producto.");
			addProduct();
		}
	}

	private void addEvaluation() {
		EvaluationListModel evaluationModel = evaluationMap.get(listProducts
				.getSelectedValue().toString());

		File file = chooseFile();

		if (file != null) {

			if (!evaluationModel.existFileName(file.getAbsolutePath())) {
				evaluationModel.addElement(file.getName());
				evaluationModel.addFileName(file.getAbsolutePath());
				listEvaluations.setModel(evaluationModel);
			} else {
				JOptionPane.showMessageDialog(this,
						"La evaluación ya se encuentra agregada.");
			}
		}
	}

	private JPanel createPanelEvaluations() {
		JPanel panelEvaluations = new JPanel();
		panelEvaluations.setLayout(null);
		panelEvaluations.setBorder(new EtchedBorder(EtchedBorder.LOWERED, null,
				null));
		panelEvaluations.setBounds(20, 185, 185, 150);

		JLabel lblEvaluations = new JLabel("Evaluaciones:");
		lblEvaluations.setFont(new Font("Tahoma", Font.BOLD, 12));
		lblEvaluations.setBounds(15, 10, 100, 15);
		panelEvaluations.add(lblEvaluations);

		listEvaluations = new JList();
		listEvaluations.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		listEvaluations.addMouseListener(new MouseAdapter() {
			public void mouseClicked(MouseEvent e) {
				if (listEvaluations.getSelectedIndex() != NOT_SELECTED) {
					btnRemoveEvaluation.setEnabled(true);
				}
			}
		});

		JScrollPane scrollPaneEvaluations = new JScrollPane();
		scrollPaneEvaluations.setBounds(55, 35, 120, 100);
		scrollPaneEvaluations.setViewportView(listEvaluations);
		panelEvaluations.add(scrollPaneEvaluations);

		btnAddEvaluation = new JButton();
		btnAddEvaluation.setEnabled(false);
		btnAddEvaluation.setToolTipText("Agregar");
		btnAddEvaluation.setBounds(15, 35, 35, 35);
		btnAddEvaluation.setIcon(getIcon(IconEnum.ADD));
		btnAddEvaluation.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if (listProducts.getSelectedIndex() != NOT_SELECTED) {
					addEvaluation();
				}
			}
		});
		panelEvaluations.add(btnAddEvaluation);

		btnRemoveEvaluation = new JButton();
		btnRemoveEvaluation.setEnabled(false);
		btnRemoveEvaluation.setToolTipText("Quitar");
		btnRemoveEvaluation.setBounds(15, 71, 35, 35);
		btnRemoveEvaluation.setIcon(getIcon(IconEnum.REMOVE));
		btnRemoveEvaluation.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				int option = JOptionPane.showConfirmDialog(
						GenerateReportsDialog.this,
						"¿Está seguro de eliminar la evaluación?");

				if (option == JOptionPane.YES_OPTION) {
					int index = listEvaluations.getSelectedIndex();
					EvaluationListModel evaluationModel = evaluationMap
							.get(listProducts.getSelectedValue().toString());
					evaluationModel.removeElementAt(index);
					evaluationModel.removeFileName(index);
					btnRemoveEvaluation.setEnabled(false);
				}
			}
		});
		panelEvaluations.add(btnRemoveEvaluation);

		return panelEvaluations;
	}

	private File chooseFile() {
		ExtensionFileFilter xlsFilter = new ExtensionFileFilter(
				"Libro de Excel", "xls");

		JFileChooser fileChooser = new JFileChooser();
		fileChooser.addChoosableFileFilter(xlsFilter);
		fileChooser.showOpenDialog(this);

		return fileChooser.getSelectedFile();
	}

	private JPanel createPanelOptions() {
		JPanel panelOptions = new JPanel();
		panelOptions.setLayout(null);
		panelOptions.setBorder(new EtchedBorder(EtchedBorder.LOWERED, null,
				null));
		panelOptions.setBounds(20, 340, 185, 130);
		
		radioButtonTotal = new JRadioButton("Calidad total");
		radioButtonTotal.setBounds(15, 10, 130, 15);
		radioButtonTotal.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				checkBoxIncludeValue.setEnabled(!radioButtonTotal.isSelected());
				checkBoxIncludeValue.setSelected(!radioButtonTotal.isSelected());
			}
		});
		panelOptions.add(radioButtonTotal);

		radioButtonChrtcs = new JRadioButton("Por característica");
		radioButtonChrtcs.setBounds(15, 30, 130, 15);
		radioButtonChrtcs.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				checkBoxIncludeValue.setEnabled(!radioButtonTotal.isSelected() 
						&& listProducts.getSelectedValues().length == 1);
			}
		});
		panelOptions.add(radioButtonChrtcs);

		radioButtonSubChrtcs = new JRadioButton("Por subcaracterística");
		radioButtonSubChrtcs.setBounds(15, 50, 150, 15);
		radioButtonSubChrtcs.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				checkBoxIncludeValue.setEnabled(!radioButtonTotal.isSelected()
						&& listProducts.getSelectedValues().length == 1);
			}
		});
		panelOptions.add(radioButtonSubChrtcs);

		ButtonGroup buttonGroup = new ButtonGroup();
		buttonGroup.add(radioButtonTotal);
		buttonGroup.add(radioButtonChrtcs);
		buttonGroup.add(radioButtonSubChrtcs);

		checkBoxIncludeValue = new JCheckBox("Incluir valores");
		checkBoxIncludeValue.setBounds(15, 70, 100, 15);
		panelOptions.add(checkBoxIncludeValue);

		JButton btnGenerate = new JButton("Generar");
		btnGenerate.setBounds(80, 100, 90, 25);
		panelOptions.add(btnGenerate);
		btnGenerate.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				try {
					generateChart();
				} catch (Exception ex) {
					Logger.getInstance().registrarLog(ex);
					JOptionPane.showMessageDialog(GenerateReportsDialog.this,
							ex.getMessage());
				}
			}
		});

		return panelOptions;
	}

	private void generateChart() throws Exception {
		if (listProducts.getSelectedIndex() >= 0) {
			char optionSelected = radioButtonTotal.isSelected() ? 'T' 
					: radioButtonChrtcs.isSelected() ? 'C'
					: radioButtonSubChrtcs.isSelected() ? 'S' : 'N';
			boolean valueSelected = checkBoxIncludeValue.isSelected();

			Map<String, Map<String, ChartData>> chartData = readCharData(
					optionSelected, valueSelected);

			CharGenerator charGenerator = CharGenerator.getInstance();
			panelChart.removeAll();
			panelChart.add(charGenerator.generateChart(chartData,
					optionSelected, valueSelected), BorderLayout.CENTER);
			panelChart.validate();
		} else {
			JOptionPane.showMessageDialog(this,
					"Debe Agregar/Seleccionar al menos un producto.");
		}
	}

	private Map<String, Map<String, ChartData>> readCharData(
			char optionSelected, boolean valueSelected) throws Exception {
		ExcelReader excelReader = ExcelReader.getInstance();
		Object[] productNames = listProducts.getSelectedValues();
		Map<String, Map<String, ChartData>> chartData = new HashMap<String, Map<String, ChartData>>();
		
		if (optionSelected != 'N') {
			for (Object productName : productNames) {
				EvaluationListModel evaluationListModel = evaluationMap.get(productName.toString());
				List<String> fileNames = evaluationListModel.getFileNames();
				
				if (!fileNames.isEmpty()) {
					Map<String, ChartData> consolidated = new HashMap<String, ChartData>();
					
					for (String fileName : fileNames) {
						ProductEvaluated excel = excelReader.readFile(fileName);
						
						if (optionSelected == 'T') {
							ChartData totalData = consolidated.get(productName.toString()) != null ? 
									consolidated.get(productName.toString()) : new ChartData();

							totalData.sumTotalQuality(excel.getQuality());
							totalData.sumCount();
							
							consolidated.put(productName.toString(), totalData);
							
						} else {
							for (Entry<CharacteristicEnum, CharacteristicEvaluated> evaluation : excel
									.getCharacteristics().entrySet()) {
								switch (optionSelected) {
								case 'C':
									ChartData characteristicData = consolidated.get(evaluation.getKey()) != null ? 
											consolidated.get(evaluation.getKey()) : new ChartData();
											
									if (valueSelected) {
										characteristicData.sumWeight(evaluation.getValue().getCharacteristic().getWeight());
										characteristicData.sumQualityVStotal(evaluation.getValue().getQualityVStotal());
									} else {
										characteristicData.sumQuality(evaluation.getValue().getQuality());								
									}
											
									characteristicData.sumCount();
									consolidated.put(evaluation.getKey().toString(), characteristicData);
									break;
								case 'S':
									for (Entry<SubCharacteristicEnum, SubCharacteristicEvaluated> subchrtcs : evaluation
											.getValue().getSubCharacteristics().entrySet()) {
										ChartData subcharacteristicData = consolidated.get(evaluation.getKey()) != null ? 
												consolidated.get(evaluation.getKey()) : new ChartData();
												
										subcharacteristicData.sumQuality(subchrtcs.getValue().getQuality());
										
										if (valueSelected) {
											subcharacteristicData.sumWeight(subchrtcs.getValue()
													.getSubCharacteristic().getWeight());
										}
										
										subcharacteristicData.sumCount();
										consolidated.put(subchrtcs.getKey().toString(), subcharacteristicData);
									}
									break;
								}							
							}							
						}						
					}	
					
					chartData.put(productName.toString(), consolidated);
				} else {
					throw new Exception(
							"Debe agregar las evaluaciones para el producto: " + productName);
				}
			}		
		} else {
			throw new Exception(
					"Debe seleccionar la opción para generar el reporte.");
		}
		
		return chartData;
	}
}
